package com.ruoyi.web.wuchuan.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import com.ruoyi.common.core.result.BusinessException;
import com.ruoyi.web.wuchuan.dto.ShapToJsonDTO;
import com.ruoyi.web.wuchuan.vo.FileVO;
import com.vividsolutions.jts.geom.*;
import org.geotools.data.FeatureWriter;
import org.geotools.data.Transaction;
import org.geotools.data.shapefile.ShapefileDataStore;
import org.geotools.data.shapefile.ShapefileDataStoreFactory;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.geotools.data.simple.SimpleFeatureSource;
import org.geotools.feature.AttributeTypeBuilder;
import org.geotools.feature.NameImpl;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.geotools.feature.type.AttributeTypeImpl;
import org.geotools.geojson.feature.FeatureJSON;
import org.geotools.geojson.geom.GeometryJSON;
import org.geotools.referencing.CRS;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.geotools.util.SimpleInternationalString;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.AttributeDescriptor;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

/**
 * @author by shixd
 * @date 2021/3/22
 * @desc
 */
@Component
public class ShapeFileUtils {
    public static final String tempPath = System.getProperty("java.io.tmpdir");

    public FileVO saveFile(MultipartFile file, String uuid) throws IOException {
        FileVO fileVO = new FileVO();
        String fileName = file.getOriginalFilename();
        File dest = createFile(fileName, uuid);
        file.transferTo(dest);
        fileVO.setFileName(dest.getName());
        fileVO.setParentPath(dest.getParentFile().getPath());
        fileVO.setPath(dest.getPath());
        return fileVO;

    }


    public File createFile(String fileName, String uuid) {

        File file = new File(tempPath + File.separator + uuid + File.separator + fileName);
        File fileParent = file.getParentFile();
        if (!fileParent.exists()) {
            fileParent.mkdirs();// 能创建多级目录
        }
        if (!file.exists()) {
            try {
                file.createNewFile();// 能创建多级目录
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return file;
    }


    /**
     * @return void 返回类型
     * @throws
     * @Description: TODO(读取Zip信息 ， 获得zip中所有的目录文件信息)
     * @param设定文件
     */
    public String zipFileRead(FileVO fileVO) {
        String shapPath = "";
        try {
            ZipFile zipFile = new ZipFile(fileVO.getPath(), StandardCharsets.UTF_8);
            Enumeration<? extends ZipEntry> enu = zipFile.entries();
            while (enu.hasMoreElements()) {
                ZipEntry zipElement = enu.nextElement();
                InputStream read = zipFile.getInputStream(zipElement);
                String fileName = zipElement.getName();
                if (fileName != null && fileName.contains(".")) {// 是否为文件
                    unZipFile(zipElement, read, fileVO.getParentPath());
                }
                if (zipElement.getName().contains(".shp")) {
                    shapPath = fileVO.getParentPath() + File.separator + zipElement.getName();
                }
            }
            zipFile.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return shapPath;
    }

    /**
     * @return void 返回类型
     * @throws
     * @Description: TODO(找到文件并读取解压到指定目录)
     */
    public void unZipFile(ZipEntry ze, InputStream read, String path
    ) throws IOException {
        File file = new File(path+File.separator+ze);
        if (!file.exists()) {
            // 写入文件
            BufferedOutputStream write = new BufferedOutputStream(
                    new FileOutputStream(file));
            int cha;
            while ((cha = read.read()) != -1) {
                write.write(cha);
            }
            // 要注意IO流关闭的先后顺序
            write.flush();
            write.close();
            read.close();
        }
    }


    /**
     * shp转换为Geojson
     *
     * @param shpPath
     * @return
     */
    public ShapToJsonDTO shape2Geojson(String shpPath) {
        ShapToJsonDTO shapToJsonDTO = new ShapToJsonDTO();
        shapToJsonDTO.setFlag(0);
        //新建json对象
        FeatureJSON fjson = new FeatureJSON();
        JSONObject geojsonObject = new JSONObject();
        geojsonObject.put("type", "FeatureCollection");
        try {
            //获取featurecollection
            File file = new File(shpPath);
            ShapefileDataStore shpDataStore;
            shpDataStore = new ShapefileDataStore(file.toURI().toURL());
            Charset charset = shpDataStore.getCharset();
            String charsetName = charset.name();
            String typeName = shpDataStore.getTypeNames()[0];
            SimpleFeatureSource featureSource;
            featureSource = shpDataStore.getFeatureSource(typeName);
            CoordinateReferenceSystem crs = shpDataStore.getSchema().getCoordinateReferenceSystem();
            String code = crs.getName().getCode();

            if (crs == null) {
                throw new BusinessException("上传文件异常无坐标prj系文件，请重新上传！");
            }
            geojsonObject.put("crs",crs);
            if(!"GCS_China Geodetic Coordinate System 2000".equals(code)){
                shapToJsonDTO.setFlag(1);
                shapToJsonDTO.setWkt(code);
            }
//            String wkt = crs.toWKT();
//            if (!"4490".equals(wkt)) {
//                shapToJsonDTO.setFlag(1);
//                shapToJsonDTO.setWkt(code);
//            }
            SimpleFeatureCollection result = featureSource.getFeatures();
            SimpleFeatureIterator itertor = result.features();
            JSONArray array = new JSONArray();
            List<String> geometries = new ArrayList<>();
            //遍历feature转为json对象
            while (itertor.hasNext()) {
                SimpleFeature feature = itertor.next();
                MultiPolygon p = (MultiPolygon)feature.getDefaultGeometry();
                geometries.add(p.toString());
                StringWriter writer = new StringWriter();
                fjson.writeFeature(feature, writer);
                String temp = writer.toString();
                byte[] b = temp.getBytes("GBK");
                temp = new String(b, "GBK");
                JSONObject json = JSON.parseObject(temp);
                array.add(json);
            }
            geojsonObject.put("geometries",geometries);
            geojsonObject.put("features", array);
            itertor.close();
            shapToJsonDTO.setData(JSON.toJSONString(geojsonObject));
            return shapToJsonDTO;
        } catch (Exception e) {
            e.printStackTrace();

        }

        return null;
    }


    public void geojson2Shape(String strJson, String shpPath) {
        GeometryJSON gjson = new GeometryJSON();

        try {
            JSONObject json = JSON.parseObject(strJson, Feature.IgnoreNotMatch);
            JSONArray features = json.getJSONArray("features");
            JSONObject feature0 = JSON.parseObject(features.getString(0), Feature.InitStringFieldAsEmpty);
            String strType = (feature0.getJSONObject("geometry")).getString("type");
            Map<String, Object> properties0 = feature0.getJSONObject("properties");

            Class<?> geoType = null;
            switch (strType) {
                case "Point":
                    geoType = Point.class;
                    break;
                case "MultiPoint":
                    geoType = MultiPoint.class;
                    break;
                case "LineString":
                    geoType = LineString.class;
                    break;
                case "MultiLineString":
                    geoType = MultiLineString.class;
                    break;
                case "Polygon":
                    geoType = Polygon.class;
                    break;
                case "MultiPolygon":
                    geoType = MultiPolygon.class;
                    break;
            }
            //创建shape文件对象
            File file = new File(shpPath);
            Map<String, Serializable> params = new HashMap<>();
            params.put(ShapefileDataStoreFactory.URLP.key, file.toURI().toURL());
            ShapefileDataStore ds = (ShapefileDataStore) new ShapefileDataStoreFactory().createNewDataStore(params);
            //设置编码
            Charset charset = StandardCharsets.UTF_8;
            ds.setCharset(charset);

            //定义图形信息和属性信息
            SimpleFeatureTypeBuilder tb = new SimpleFeatureTypeBuilder();
            tb.setCRS(CRS.decode("EPSG:4490"));
            tb.setName("shapefile");
            tb.add("the_geom", geoType);
            tb.add("gid", Long.class);

            List<AttributeDescriptor> attributeDesList = new ArrayList<>();
            for (Map.Entry<String, Object> entry : properties0.entrySet()) {
                //属性构造器
                AttributeTypeBuilder build = new AttributeTypeBuilder();
                String name = entry.getKey();
                build.setName(name);
                build.setBinding(entry.getValue().getClass());
                build.setDescription(name);
                AttributeTypeImpl type = new AttributeTypeImpl(new NameImpl(name), entry.getValue().getClass(),
                        true, true, null, build.buildType(), new SimpleInternationalString(name));
                AttributeDescriptor descriptor = build.buildDescriptor(name, type);
                attributeDesList.add(descriptor);

            }
            tb.addAll(attributeDesList);

            ds.createSchema(tb.buildFeatureType());


            try ( //设置Writer

                  FeatureWriter<SimpleFeatureType, SimpleFeature> writer = ds.getFeatureWriter(ds.getTypeNames()[0], Transaction.AUTO_COMMIT)) {

                int index = 0;
                for (Object o : features) {
                    JSONObject feature = (JSONObject) o;
                    Map<String, Object> properties = feature.getJSONObject("properties");
                    String strFeature = feature.toString();
                    Geometry geometry = gjson.read(strFeature);
                    SimpleFeature simpleFeature = writer.next();
                    simpleFeature.setAttribute("the_geom", geometry);
                    simpleFeature.setAttribute("gid", index);
                    simpleFeature.setAttribute("gid", index);
                    Set<Map.Entry<String, Object>> a = properties.entrySet();
                    for (Map.Entry<String, Object> entry : a) {
                        String as = entry.getKey();
                        if(as.length() > 10){
                            as = as.substring(0, 10);
                        }
                        Object aa = entry.getValue();
                        simpleFeature.setAttribute(as, aa);
                    }
                    writer.write();
                    index++;
                }
            }
            ds.dispose();

        } catch (Exception e) {

            e.printStackTrace();
        }
    }

    public boolean deleteFile(String filePath) {
        File file = new File(filePath);
        if (!file.exists()) {
            return false;
        }
        if (file.isFile()) {
            return file.delete();
        }
        File[] files = file.listFiles();
        assert files != null;
        for (File f : files) {
            if (f.isFile()) {
                if (!f.delete()) {
                    return false;
                }
            } else {
                if (!deleteFile(f.getAbsolutePath())) {
                    return false;
                }
            }
        }
        return file.delete();
    }

    /**
     * 压缩zip可直接指定路径
     *
     * @param output
     * @throws Exception
     */
    public void zips(String output, String fileName, List<String> rootPath) throws IOException {

        //要生成的压缩文件
        ZipOutputStream out = new ZipOutputStream(new FileOutputStream(output));
        byte[] buffer = new byte[1024 * 5];
        List<File> sourceFilelist = new ArrayList<>();
        if (rootPath.size() == 1 && !rootPath.get(0).contains(".pdf")) {
            File sourceFile = new File(rootPath.get(0));  //源文件地址
            File[] sourceFiles = sourceFile.listFiles();
            assert sourceFiles != null;
            for (File file : sourceFiles) {
                if (file.getName().endsWith(".zip")) {
                    continue;
                }
                String fileName1 = file.getName().substring(0,file.getName().lastIndexOf("."));
                if(!fileName.equals(fileName1)){
                        continue;
                }
                FileInputStream fis = new FileInputStream(file);
                out.putNextEntry(new ZipEntry(file.getName()));  //zip生成后内层目录
                int len;
                // 读入需要下载的文件的内容，打包到zip文件
                while ((len = fis.read(buffer)) > 0) {
                    out.write(buffer, 0, len);
                }
                out.closeEntry();
                fis.close();
            }
        } else {
            for (String filename : rootPath) {
                File file = new File(filename);
                FileInputStream fis = new FileInputStream(file);
                String name = file.getName();
                if(name.contains("temp")||name.contains("tmp")){
                    name = name.replaceFirst("tmp","");
                }
                out.putNextEntry(new ZipEntry(name));  //zip生成后内层目录
                int len;
                // 读入需要下载的文件的内容，打包到zip文件
                while ((len = fis.read(buffer)) > 0) {
                    out.write(buffer, 0, len);
                }
                out.closeEntry();
                fis.close();
            }
        }

        out.close();
    }


}
